﻿/*
 * @author: wizardc
 */

using System.Collections.Generic;
using Dou.Clock;
using Dou.Utils;

namespace Dou.Timer
{
    /// <summary>
    /// 计时器类
    /// </summary>
    class Timer : IClockClient
    {
        static Timer()
        {
            Recyclable.Register<TimerInfo>(50, () => new TimerInfo());
        }

        private Dictionary<int, TimerInfo> _map;
        private List<TimerInfo> _list;
        private int _id = 0;

        public Timer()
        {
            _map = new Dictionary<int, TimerInfo>();
            _list = new List<TimerInfo>();
        }

        public int AddTimer(int repeatCount, float time, TimerCallback callback, params object[] args)
        {
            if (repeatCount == 0 || time <= 0)
            {
                return -1;
            }
            TimerInfo timer = Recyclable.Get<TimerInfo>();
            timer.id = ++_id;
            timer.repeatCount = repeatCount;
            timer.time = time;
            timer.nowTime = time;
            timer.callback = callback;
            timer.args = args;
            _map[timer.id] = timer;
            _list.Add(timer);
            return _id;
        }

        public void Update(float passedTime)
        {
            if (_list.Count == 0)
            {
                return;
            }
            int currentIndex = 0;
            int i = 0;
            for (; i < _list.Count; i++)
            {
                TimerInfo timer = _list[i];
                if (timer != null)
                {
                    if (currentIndex != i)
                    {
                        _list[currentIndex] = timer;
                        _list[i] = null;
                    }
                    currentIndex++;
                    timer.nowTime -= passedTime;
                    while (timer.nowTime < 0)
                    {
                        timer.callback(timer.args);
                        if (timer.repeatCount > 0)
                        {
                            timer.repeatCount--;
                        }
                        if (timer.repeatCount == 0)
                        {
                            Recyclable.Recycle(timer);
                            _map.Remove(timer.id);
                            _list[i] = null;
                            break;
                        }
                        timer.nowTime += timer.time;
                    }
                }
            }
            if (currentIndex != i)
            {
                while (i < _list.Count)
                {
                    _list[currentIndex++] = _list[i++];
                }
                _list.RemoveRange(currentIndex, _list.Count - currentIndex);
            }
        }

        public void RemoveTimer(int id)
        {
            TimerInfo timer = _map[id];
            if (timer != null)
            {
                Recyclable.Recycle(timer);
                _map.Remove(id);
                int index = _list.IndexOf(timer);
                _list[index] = null;
            }
        }
    }

    class TimerInfo : ICacheable
    {
        public int id;
        public int repeatCount;
        public float time;
        public float nowTime;
        public TimerCallback callback;
        public object[] args;

        public void OnRecycle()
        {
            id = 0;
            repeatCount = 0;
            time = 0;
            nowTime = 0;
            callback = null;
            args = null;
        }

        public void OnReuse()
        {
        }
    }
}
